;
;  PROGRAM:  CRC
;  VERSION:  2.0
;  DATE:  16 Jan 83
;  AUTHOR:  RICHARD CONN
;  PREVIOUS VERSIONS:  1.2 (6 Jan 83), 1.1 (1 Jan 83), 1.0 (12 Dec 82)
;
VERS	equ	20

;
;	This program is Copyright (c) 1982, 1983 by Richard Conn
;	All Rights Reserved
;
;	ZCPR2 and its utilities, including this one, are released
; to the public domain.  Anyone who wishes to USE them may do so with
; no strings attached.  The author assumes no responsibility or
; liability for the use of ZCPR2 and its utilities.
;
;	The author, Richard Conn, has sole rights to this program.
; ZCPR2 and its utilities may not be sold without the express,
; written permission of the author.
;


;
;  CRC Command --
;	CRC is used to compute the CRC of one or more files.  CRC
; permits ambiguous file names and supports an Inspect mode that
; allows the user to confirm each file before the computation is done.
; Additionally, there is a Disk Output Mode which allows the user to send
; the output from the operation to disk as well as to his screen with optional
; comments.
;
;	The CRC command may be of the following forms:
;		CRC dir:afn,dir:afn1,... o
;	CRCs are computed for the indicated sets of files in the indicated
; directories.
;
;	The option characters (o) are none or more of the following:
;		C -- Comment Output; add comments if output is to disk
;		D -- Disk Output; send output to disk file CRCKLIST.CRC
;		I -- Inspect and approve each rename
;		P -- Printer Output
;
;	Examples:
;		CRC A1:MYFILE.*,B2:HELLO.TXT	<-- Compute CRCs of files
;		CRC *.* DC			<-- CRCs of all files in
;						    current user/disk with
;						    disk output and comments
;		CRC *.* DCI			<-- As above, but inspect and
;						    approve files first
;

FALSE	EQU	0
TRUE	EQU	NOT FALSE

ESIZE	EQU	16	; SIZE OF DIR ENTRY (FROM SYSLIB DIRF ROUTINE)

	EXT	DIRFS	; DIRECTORY PROCESSOR
	EXT	DIRPACK	; PACK DIRECTORY
	EXT	FSIZE	; COMPUTE FILE SIZE

	EXT	ZGPINS	; INIT BUFFERS
	EXT	ZFNAME	; FILE NAME PROCESSOR

	EXT	FO0$OPEN	; OPEN FILE FOR BYTE-ORIENTED OUTPUT
	EXT	FO0$CLOSE	; CLOSE FILE
	EXT	F0$PUT		; WRITE BYTE TO FILE

	EXT	F$MAKE	; CREATE FILE
	EXT	F$OPEN	; OPEN FILE
	EXT	F$READ	; READ BLOCK FROM FILE
	EXT	F$CLOSE	; CLOSE FILE
	EXT	F$DELETE	; DELETE FILE

	EXT	CONDIN	; CONDITIONAL INPUT

	EXT	MA2HC	; MEMORY STORE OF A AS 2 HEX CHARS
	EXT	MHLDC	; MEMORY STORE OF HL AS UP TO 5 DEC CHARS W/LEADING SP

	EXT	BBLINE	; INPUT LINE EDITOR
	EXT	INITFCB	; INIT FCB
	EXT	BDOS	; BDOS ENTRY
	EXT	RETUD	; RETURN CURRENT USER/DISK
	EXT	PUTUD	; SAVE CURRENT USER/DISK
	EXT	GETUD	; RESTORE CURRENT USER/DISK
	EXT	LOGUD	; LOG INTO USER/DISK
	EXT	MOVEB	; COPY ROUTINE
	EXT	PRINT	; PRINT STRING PTED TO BY RET ADR
	EXT	LOUT	; LST: OUTPUT ROUTINE
	EXT	COUT	; CONSOLE OUTPUT ROUTINE
	EXT	CIN	; CONSOLE INPUT ROUTINE
	EXT	CAPS	; CAPITALIZE ROUTINE
	EXT	CRLF	; NEW LINE ROUTINE
	EXT	CODEND	; CODE END COMPUTATION ROUTINE

;
;  CP/M EQUATES
;
CPM	EQU	0	; WARM BOOT
FCB	EQU	5CH	; FCB
TBUFF	EQU	80H	; INPUT LINE BUFFER
CR	EQU	13	; <CR>
LF	EQU	10	; <LF>
CTRLC	EQU	3	; ^C

;
;  Branch to Start of Program
;
	JMP	START

;
;******************************************************************
;
;  SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format
;
;	This data block precisely defines the data format for
; initial features of a ZCPR2 system which are required for proper
; initialization of the ZCPR2-Specific Routines in SYSLIB.
;

;
;  EXTERNAL PATH DATA
;
EPAVAIL:
	DB	0FFH	; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES)
EPADR:
	DW	40H	; ADDRESS OF EXTERNAL PATH IF AVAILABLE

;
;  INTERNAL PATH DATA
;
INTPATH:
	DB	0,0	; DISK, USER FOR FIRST PATH ELEMENT
			; DISK = 1 FOR A, '$' FOR CURRENT
			; USER = NUMBER, '$' FOR CURRENT
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0
	DB	0,0	; DISK, USER FOR 8TH PATH ELEMENT
	DB	0	; END OF PATH

;
;  MULTIPLE COMMAND LINE BUFFER DATA
;
MCAVAIL:
	DB	0FFH	; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE?
MCADR:
	DW	0FF00H	; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE

;
;  DISK/USER LIMITS
;
MDISK:
	DB	4	; MAXIMUM NUMBER OF DISKS
MUSER:
	DB	31	; MAXIMUM USER NUMBER

;
;  FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK
;
DOK:
	DB	0FFH	; ALLOW DISK CHANGE? (0=NO, 0FFH=YES)
UOK:
	DB	0FFH	; ALLOW USER CHANGE? (0=NO, 0FFH=YES)

;
;  PRIVILEGED USER DATA
;
PUSER:
	DB	10	; BEGINNING OF PRIVILEGED USER AREAS
PPASS:
	DB	'chdir',0	; PASSWORD FOR MOVING INTO PRIV USER AREAS
	DS	41-($-PPASS)	; 40 CHARS MAX IN BUFFER + 1 for ending NULL

;
;  CURRENT USER/DISK INDICATOR
;
CINDIC:
	DB	'$'	; USUAL VALUE (FOR PATH EXPRESSIONS)

;
;  DMA ADDRESS FOR DISK TRANSFERS
;
DMADR:
	DW	80H	; TBUFF AREA

;
;  NAMED DIRECTORY INFORMATION
;
NDRADR:
	DW	00000H	; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY
NDNAMES:
	DB	64	; MAX NUMBER OF DIRECTORY NAMES
DNFILE:
	DB	'NAMES   '	; NAME OF DISK NAME FILE
	DB	'DIR'		; TYPE OF DISK NAME FILE

;
;  REQUIREMENTS FLAGS
;
EPREQD:
	DB	0FFH	; EXTERNAL PATH?
MCREQD:
	DB	000H	; MULTIPLE COMMAND LINE?
MXREQD:
	DB	0FFH	; MAX USER/DISK?
UDREQD:
	DB	000H	; ALLOW USER/DISK CHANGE?
PUREQD:
	DB	000H	; PRIVILEGED USER?
CDREQD:
	DB	0FFH	; CURRENT INDIC AND DMA?
NDREQD:
	DB	0FFH	; NAMED DIRECTORIES?
Z2CLASS:
	DB	0	; CLASS 0
	DB	'ZCPR2'
	DS	10	; RESERVED

;
;  END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA
;
;******************************************************************
;

;
;  DISK OUTPUT FCB
;
DSKFCB:
	DB	0
	DB	'CRC     '	; FILE NAME
	DB	'CRC'		; FILE TYPE
	DS	4
	DS	16
	DS	4	; 36 BYTES

;
;  Start of Program
;
START:
	LXI	H,0	; GET STACK PTR
	DAD	SP
	SHLD	STACK	; SAVE IT
	LXI	SP,STACK	; SET SP
	CALL	PUTUD	; SAVE CURRENT USER/DISK AWAY
	CALL	RETUD	; GET CURRENT USER/DISK
	MOV	A,B	; SAVE DISK
	STA	DISK
	MOV	A,C	; SAVE USER
	STA	USER

	CALL	ZGPINS	; INIT BUFFERS
	CALL	PRINT
	DB	'CRC  Version '
	DB	VERS/10+'0','.',(VERS MOD 10)+'0',0
	LDA	FCB+1	; GET FIRST CHAR OF FILE NAME
	CPI	' '	; NO FILE SPEC?
	JZ	HELP
	CPI	'/'	; OPTION CAUGHT?
	JNZ	ECONT

;  PRINT HELP INFORMATION
HELP:
	CALL	PRINT
	DB	CR,LF,'CRC Command --'
	DB	CR,LF,'	CRC dir:afn1,dir:afn2,... o...'
	DB	CR,LF,LF,'d is disk, u is user, and o is one or more option '
	DB	'letters.'
	DB	CR,LF,'If one or more options are specified, the o MUST be '
	DB	'preceded by a space.'
	DB	CR,LF,'Nothing is required, and wild cards (?,*) are '
	DB	CR,LF,'permitted.  o is optional, and valid options are -'
	DB	CR,LF,'	C -- Comment Mode (Allow user to comment each entry '
	DB	'on disk)'
	DB	CR,LF,'	D -- Disk Output (Send Output to Disk in file CRC.CRC'
	DB	CR,LF,'	I -- Inspect Mode (Give user approval option)'
	DB	CR,LF,'	P -- Printer Output'
	DB	CR,LF,'dir: is a named directory or the form du:.'
	DB	CR,LF,'If u is omitted, current user is assumed, as with d.'
	DB	CR,LF,0

;  RETURN TO OS
RETURN:
	LHLD	STACK	; GET OLD STACK
	SPHL		; SET IT
	RET

;
;  SKIP UNTIL NON-BLANK
;
SBLANK:
	MOV	A,M	; LOOK FOR BLANK
	INX	H	; PT TO NEXT
	CPI	' '	; BLANK?
	JZ	SBLANK
	DCX	H	; BACK UP
	RET

;
;  SKIP UNTIL BLANK OR EOL
;
SNBLANK:
	MOV	A,M	; GET CHAR
	INX	H	; PT TO NEXT
	CPI	' '	; BLANK?
	JZ	SNB1
	ORA	A	; EOL?
	JNZ	SNBLANK
SNB1:
	DCX	H	; BACK UP
	RET

;
;  PLACE ZERO AT END OF BUFFER
;
ECONT:
	LXI	H,TBUFF	; PT TO BUFFER
	MOV	A,M	; GET COUNT
	INX	H	; PT TO FIRST CHAR
	ADD	L	; PT TO END OF BUFFER
	MOV	L,A
	MOV	A,H
	ACI	0
	MOV	H,A
	MVI	M,0

;  COPY BUFFER INTO TEMP BUFFER
	LXI	H,TBUFF	; PT TO BUFFER
	MOV	B,M	; GET CHAR COUNT
	INX	H	; PT TO FIRST CHAR
	INR	B	; ADD ENDING 0
	LXI	D,CMDLNE	; PT TO CMDLNE BUFFER
	CALL	MOVEB	; COPY INTO COMMAND LINE BUFFER

;  EXTRACT FLAGS IF PRESENT
	XRA	A	; A=0
	STA	INSPECT	; SET NO INSPECT
	STA	COMMENT	; SET NO COMMENT MODE
	STA	PRTOUT	; SET NO PRINTER OUTPUT
	STA	DSKOUT	; SET NO DISK OUTPUT
	LXI	H,0	; SET FILE COUNT
	SHLD	FILECNT
	LXI	H,CMDLNE	; PT TO BUFFER
;
;  SKIP TO FILE NAME STRING
;
	CALL	SBLANK	; SKIP OVER BLANKS
;
;  SKIP TO END OF FILE NAME STRING
;
	CALL	SNBLANK	; SKIP OVER NON-BLANKS
;
;  CHECK FOR LEADING SLASH ON OPTION AND SKIP IT IF SO
;
OPT:
	CPI	'/'	; OPTION CHAR?
	JNZ	OPTION
	INX	H	; SKIP SLASH
;  PROCESS LIST OF OPTIONS
OPTION:
	MOV	A,M	; GET BYTE
	ORA	A	; DONE?
	JZ	DSPEC
	INX	H	; PT TO NEXT CHAR
	CPI	' '	; SKIP OVER SPACES
	JZ	OPTION
	CPI	'/'	; IF OPTION LETTER, OBVIOUS ERROR, SO HELP
	JZ	HELP
	CPI	'P'	; PRINTER OUTPUT?
	JZ	OPTPRT
	CPI	'C'	; COMMENT?
	JZ	OPTCMT
	CPI	'I'	; INSPECT?
	JZ	OPTINS
	CPI	'D'	; DISK OUTPUT?
	JNZ	HELP
	MVI	A,0FFH	; DISK OUTPUT
	STA	DSKOUT
	JMP	OPTION
OPTPRT:
	MVI	A,0FFH	; PRINTER OUTPUT
	STA	PRTOUT
	JMP	OPTION
OPTCMT:
	MVI	A,0FFH	; COMMENT MODE
	STA	COMMENT
	JMP	OPTION
OPTINS:
	MVI	A,0FFH	; INSPECT
	STA	INSPECT
	JMP	OPTION

;
;  EXTRACT DISK, USER, AND FILE NAME INFORMATION
;
DSPEC:
	LDA	DSKOUT	; DISK OUTPUT?
	ORA	A	; Z=NO
	JZ	DSPEC0
	LXI	D,DSKFCB	; OUTPUT FCB
	CALL	INITFCB		; CLEAR FCB
	CALL	F$DELETE	; DELETE FILE
	CALL	INITFCB		; CLEAR FCB
	CALL	F$MAKE		; CREATE FILE
	CALL	FO0$OPEN	; OPEN FILE
DSPEC0:
	LXI	H,CMDLNE	; PT TO FIRST BYTE
	CALL	SBLANK	; SKIP TO NON-BLANK
;
;  MAJOR REENTRY POINT WHEN FILE SPECS ARE SEPARATED BY COMMAS
;    HL PTS TO FIRST BYTE OF NEXT FILE SPEC
;
DSPEC1:
	CALL	GETUD	; RESET USER IF NECESSARY
	LXI	D,NTFCB	; PT TO FCB IN DE, PT TO FIRST CHAR OF FILE NAME IN HL

	CALL	ZFNAME	; EXTRACT FILE NAME INTO FCB, AND GET DISK AND USER
	JZ	DERR	; ERROR HANDLER

	SHLD	NEXTCH	; SAVE PTR TO DELIMITER WHICH ENDED SCAN
	MOV	A,B	; SAVE POSSIBLE DRIVE SPEC
	CPI	0FFH	; CURRENT DISK?
	JZ	DSPEC2
	LDA	MDISK	; GET MAX DISK NUMBER
	DCR	B	; ADJUST TO WITHIN BOUNDS 0-15
	CMP	B	; WITHIN BOUNDS?
	MOV	A,B	; GET DISK NUMBER IN A
	JNC	USPEC
DERR:
	CALL	PRINT
	DB	CR,LF,'Invalid Drive or User Specification',0
	JMP	DRETURN

;
;  SET CURRENT DISK
;
DSPEC2:
	LDA	DISK	;GET CURRENT DISK
	MOV	B,A	;... IN B

;  CHECK FOR USER NUMBER
USPEC:
	MOV	A,C	; GET NEW USER NUMBER
	CPI	0FFH	; DEFAULT USER?
	JZ	USPEC1
	CPI	'?'	; ALL USERS NOT ALLOWED?
	JZ	UERR
	LDA	MUSER	; GET MAX USER NUMBER
	CMP	C
	MOV	A,C	; USER NUMBER IN A
	JNC	FCT
UERR:
	CALL	PRINT
	DB	CR,LF,'Invalid User Number',0
	JMP	DRETURN
USPEC1:
	LDA	USER	;GET CURRENT USER
	MOV	C,A	;... IN C

;
;  LOAD DIRECTORY AND PERFORM FUNCTION
;
FCT:
	MOV	A,B	; SAVE NEW DISK/USER AWAY
	STA	CDISK	; CURRENT DISK
	MOV	A,C
	STA	CUSER	; CURRENT USER
	CALL	LOGUD	; LOG INTO ACCOUNT
	CALL	CODEND	; PT TO END OF CODE
	CALL	RETUD	; GET USER NUMBER FOR DIRFS
	MVI	A,11000000B	; SELECT SYS AND NON-SYS FILES
	ORA	C	; OR IN USER NUMBER
	LXI	D,NTFCB	; PT TO FCB
	CALL	INITFCB	; INIT THE FCB
	CALL	DIRFS	; LOAD DIR, SELECT FILES, PACK, AND ALPHABETIZE
	CALL	ICHECK	; CHECK FOR INSPECT OPTION AND INSPECT IF SET
	CALL	GETUD	; RETURN TO BASE USER/DISK

;
;  PERFORM FUNCTION; HL PTS TO FILE AND BC CONTAINS NUMBER OF FILES
;
FCTL:
	MOV	A,B		; CHECK FOR COMPLETION (COUNT = 0)
	ORA	C
	JZ	FCTL1
	DCX	B		; COUNT DOWN
	PUSH	H		; SAVE PTR AND COUNT
	PUSH	B
	CALL	FUNCTION	; PERFORM FUNCTION
	POP	B		; GET COUNT AND PTR
	POP	H
	LXI	D,ESIZE		; PT TO NEXT ENTRY
	DAD	D
	JMP	FCTL

;
;  CHECK FOR NEXT FILE SPEC
;
FCTL1:
	LHLD	NEXTCH	; GET PTR
	MOV	A,M	; GET DELIM
	CPI	','	; ANOTHER FILE?
	JNZ	DRETURN
	INX	H	; PT TO CHAR AFTER COMMA
	JMP	DSPEC1	; CONTINUE PROCESSING

;
;  FUNCTION COMPLETE -- EXIT
;
DRETURN:
	CALL	DCRLF	; NEW LINE
	LDA	DSKOUT	; DISK OUTPUT USED?
	ORA	A	; NZ=YES
	CNZ	FO0$CLOSE	; CLOSE FILE
	JMP	RETURN

;
;  EMERGENCY ABORT
;
ABORT:
	CALL	PRINT
	DB	CR,LF,'** CRC Abort **',CR,LF,0
	CALL	GETUD	; RETURN HOME
	JMP	DRETURN

;
;  FUNCTION -- COMPUTE CRCS OF SELECTED FILES
;
FUNCTION:

;
;  PRINT FILE NAME
;
CRCLP:
	CALL	DCRLF	;NEW LINE
	PUSH	H	;SAVE PTR
	LHLD	FILECNT		; INCREMENT FILE COUNT
	INX	H
	SHLD	FILECNT
	CALL	DVAL	;OUTPUT DECIMAL VALUE
	POP	H	;GET PTR
	CALL	DPRINT
	DB	' File: ',0
	CALL	PRFN	; PRINT FILE NAME
	CALL	DPRINT
	DB	' -- Size: ',0
	CALL	FSIZE	; COMPUTE SIZE IN DE
	XCHG		; HL=SIZE
	CALL	DVAL	; OUTPUT VALUE
	MVI	A,'K'	; OUTPUT K
	CALL	DOUT
	XCHG		; HL = PTR TO FIRST BYTE OF FILE FCB PART
	LXI	D,CRCFCB	; COPY INTO FCB
	MVI	B,12	; 12 BYTES
	CALL	MOVEB
	XRA	A	; ZERO FIRST BYTE
	STAX	D	; SELECT CURRENT DISK OF CRCFCB

;
;  TEST FOR COMMENT AND DISK OUTPUT, AND ACCEPT COMMENT IF SET
;
CTEST:
	LDA	COMMENT	; GET FLAG
	MOV	B,A	; ... IN B
	LDA	DSKOUT	; GET FLAG
	ANA	B	; AND
	JZ	DOIT	; NO COMMENT IF ONE OR THE OTHER IS ZERO
	CALL	PRINT
	DB	CR,LF,'	Comment? ',0
	XRA	A	; DON'T CAPITALIZE
	CALL	BBLINE	; GET LINE FROM USER
	CALL	CRLF	; NEW LINE
	LXI	D,CMTLNE	; COPY INTO COMMENT LINE BUFFER FOR NOW
CTEST1:
	MOV	A,M	; GET CHAR
	STAX	D	; PUT CHAR
	ORA	A	; END?
	JZ	DOIT
	INX	H	; PT TO NEXT
	INX	D
	JMP	CTEST1

;
;  PRINT FILE NAME PTED TO BY HL
;	OUTPUT TO CON: AND OPTIONALLY DISK
;
PRFN:
	PUSH	H	; SAVE PTR
	INX	H	; PT TO FILE NAME
	MVI	B,8	; PRINT NAME
	CALL	PRNT
	MVI	A,'.'	; DECIMAL
	CALL	DOUT
	MVI	B,3	; PRINT TYPE
	CALL	PRNT
	POP	H	; GET PTR
	RET

;
;  PRINT CHARS PTED TO BY HL FOR B BYTES
;	OUTPUT TO CON: AND OPTIONALLY DISK
;
PRNT:
	MOV	A,M	; GET CHAR
	CALL	DOUT
	INX	H	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	PRNT
	RET

;
;  PRINT FILE NAME PTED TO BY HL
;	OUTPUT TO CON:
;
PRFNC:
	PUSH	H	; SAVE PTR
	INX	H	; PT TO FILE NAME
	MVI	B,8	; PRINT NAME
	CALL	PRNTC
	MVI	A,'.'	; DECIMAL
	CALL	COUT
	MVI	B,3	; PRINT TYPE
	CALL	PRNTC
	POP	H	; GET PTR
	RET

;
;  PRINT CHARS PTED TO BY HL FOR B BYTES
;	OUTPUT TO CON:
;
PRNTC:
	MOV	A,M	; GET CHAR
	CALL	COUT
	INX	H	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	PRNTC
	RET

;
;  CHECK FOR INSPECT OPTION AND INSPECT FILES IF SET
;    FIRST FILE PTED TO BY HL, COUNT IN BC
;
ICHECK:
	LDA	INSPECT	; INSPECT?
	ORA	A	; 0=NO
	RZ
	CALL	PRINT
	DB	CR,LF,CR,LF,'** File Inspection **',0
	PUSH	H	; SAVE POINTER TO FIRST FILE
	PUSH	B	; SAVE FILE COUNT
ICKL:
	PUSH	B	; SAVE COUNT
	CALL	CRLF	; NEW LINE
	CALL	PRFNC	; PRINT FILE NAME TO CONSOLE ONLY
	CALL	CRCQ	; CRC QUESTION
	POP	B	; GET COUNT
	CPI	'S'	; SKIP REST?
	JZ	ISKIP
	CPI	'Q'	; QUIT?
	JZ	QUIT
	CPI	'N'	; NO?
	JZ	NODO
	CALL	PRINT
	DB	'	Selected',0
	MOV	A,M	; GET BYTE
	ORI	80H	; SET MSB
	MOV	M,A	; PUT BYTE
	JMP	ICKNXT

;  DON'T CRC FILE
NODO:
	CALL	PRINT
	DB	'	NOT Selected',0

;  CONTINUE SCAN OF FILES
ICKNXT:
	LXI	D,16	; SIZE OF FILE ENTRY
	DAD	D	; PT TO NEXT ENTRY
	DCX	B	; COUNT DOWN
	MOV	A,B	; DONE?
	ORA	C
	JNZ	ICKL
ISKIP:
	POP	B	; RESTORE ORIGINAL COUNT
	POP	H	; RESTORE PTR TO FIRST FILE
	CALL	DIRPACK	; PACK DIRECTORY BASED ON SELECTION
	CALL	PRINT
	DB	CR,LF,'** Inspection Complete **',CR,LF,0
	RET

;
;  PROMPT USER FOR INSPECT
;
CRCQ:
	CALL	PRINT	; PRINT PROMPT
	DB	' -- Select (Y/N/S=Skip Rest/Q=Quit/other=Y)? ',0
	CALL	CIN	; GET RESPONSE
	CALL	CAPS	; CAPITALIZE
	CALL	COUT	; ECHO
	RET

;
;  QUIT CRC PROGRAM
;
QUIT:
	CALL	PRINT
	DB	'	Quit to ZCPR2',0
	JMP	DRETURN

;
;  COMPUTE CRC; NAME IN CRCFCB
;
DOIT:
	LDA	CDISK		; LOG INTO PROPER DISK AND USER
	MOV	B,A
	LDA	CUSER
	MOV	C,A
	CALL	LOGUD
	CALL	CRCCLR		; CLEAR CRC ACCUMULATOR
	LXI	D,CRCFCB	; PT TO FCB
	CALL	INITFCB		; INIT IT
	CALL	F$OPEN		; OPEN IT FOR INPUT
DOITL:
	CALL	F$READ		; READ BLOCK INTO TBUFF
	ORA	A		; ERROR?
	JNZ	DOITD		; DONE IF SO
	CALL	CONDIN		; CHECK FOR ABORT
	JZ	DOITL0
	CPI	CTRLC		; ABORT?
	JZ	ABORT		; QUICK ABORT
DOITL0:
	LXI	H,TBUFF		; PT TO FIRST BYTE
	MVI	B,128		; 128 BYTES
DOITL1:
	MOV	A,M		; GET BYTE
	CALL	CRCUPD		; UPDATE CRC
	INX	H		; PT TO NEXT
	DCR	B		; COUNT DOWN
	JNZ	DOITL1
	JMP	DOITL		; CONTINUE THRU FILE
DOITD:
	CALL	GETUD		; RETURN TO HOME DIRECTORY
	CALL	DPRINT
	DB	' -- CRC: ',0
	CALL	CRCDONE		; RETURN CRC IN HL
	CALL	HVAL		; PRINT VALUE AS HEX
	LDA	COMMENT		; CHECK FOR DISK AND COMMENT AND OUTPUT IF SO
	MOV	B,A		; FLAG IN B
	LDA	DSKOUT
	ANA	B		; ZERO IF ONE NOT SELECTED
	RZ			; DONE IF ONE NOT SELECTED
	CALL	DPRINT
	DB	CR,LF,'	Comment: ',0
	LXI	H,CMTLNE	; OUTPUT COMMENT LINE
CMTLP:
	MOV	A,M		; GET CHAR
	ORA	A		; EOL?
	RZ			; EXIT WHEN DONE
	CALL	DOUT		; OUTPUT CHAR
	INX	H		; PT TO NEXT
	JMP	CMTLP

;
;  OUTPUT CHAR TO CONSOLE AND OPTIONALLY PRINTER OR DISK
;
DOUT:
	PUSH	PSW	; SAVE CHAR
	PUSH	B	; SAVE BC
	MOV	B,A	; CHAR IN B
	CALL	COUT	; OUTPUT TO CONSOLE
	LDA	PRTOUT	; PRINTER OUTPUT?
	ORA	A	; Z=NO
	JZ	DOUT1
	MOV	A,B	; GET CHAR
	CALL	LOUT	; OUTPUT TO PRINTER
DOUT1:
	LDA	DSKOUT	; DISK OUTPUT?
	ORA	A	; Z=NO
	JZ	DOUT2
	MOV	A,B	; GET CHAR
	CALL	F0$PUT	; OUTPUT TO DISK
DOUT2:
	POP	B	; RESTORE REGS
	POP	PSW
	RET

;
;  OUTPUT CHARS PTED TO BY RET ADR TO CONSOLE AND DISK OR PRINTER
;
DPRINT:
	XTHL		; GET PTR AND SAVE HL AT SAME TIME
DPRL:
	MOV	A,M	; GET CHAR
	INX	H	; PT TO NEXT
	ORA	A	; END?
	JZ	DPRL1
	CALL	DOUT	; OUTPUT IT
	JMP	DPRL
DPRL1:
	XTHL		; SET RET ADR AND RESTORE HL
	RET

;
;  NEW LINE TO ALL
;
DCRLF:
	PUSH	PSW	; SAVE PSW
	MVI	A,CR	; NEW LINE
	CALL	DOUT
	MVI	A,LF
	CALL	DOUT
	POP	PSW	; RESTORE PSW
	RET

;
;  OUTPUT VALUE IN HL TO ALL IN HEX
;
HVAL:
	PUSH	H	; SAVE HL
	PUSH	D	; SAVE DE
	LXI	D,NUMBUF	; PT TO NUMBER BUFFER
	MOV	A,H
	CALL	MA2HC	; OUTPUT IN HEX
	MVI	A,' '	; STORE SPACE
	STAX	D
	INX	D	; PT TO NEXT
	MOV	A,L
	CALL	MA2HC
	JMP	DVAL0

;
;  OUTPUT HL AS UP TO 5 DECIMAL DIGITS TO ALL
;
DVAL:
	PUSH	H	; SAVE REGS
	PUSH	D
	LXI	D,NUMBUF	; PT TO BUFFER
	CALL	MHLDC	; OUTPUT IN DECIMAL
DVAL0:
	LXI	H,NUMBUF	; PT TO BUFFER
	MVI	D,5	; 5 CHARS
DVAL1:
	MOV	A,M	; GET CHAR
	INX	H	; PT TO NEXT
	CALL	DOUT	; OUTPUT IT
	DCR	D	; COUNT DOWN
	JNZ	DVAL1
	POP	D	; RESTORE REGS
	POP	H
	RET

;
;  **** START OF CRC ROUTINES ****
;

;
;  CRCCLR -- Clear CRC Accumulator
;
;  No Registers are Affected
;
CRCCLR:
	PUSH	H	;SAVE HL
	LXI	H,0	;INIT TO ZERO
	SHLD	CRCACC
	POP	H
	RET

;
;  CRCDONE -- Return the CRC Value in HL
;
CRCDONE:
	LHLD	CRCACC	;GET VALUE
	RET

;
;  CRCUPD -- Update CRC Accumulator
;
;An 8080 routine for generating a CYCLIC-REDUNDANCY-CHECK.
;Adapted from Keith Petersen's CRCK 4.2 program.
;By Fred Gutman.
;From 'EDN' magazine, June 5, 1979 issue, page 84.
;
;  Byte to be updated is passed in A
;  No Registers are Affected
;
CRCUPD:
	PUSH	H	;SAVE HL
	PUSH	B	;SAVE BC
	PUSH	PSW	;SAVE BYTE TO UPDATE
	MOV	B,A	;BYTE IN B
	LHLD	CRCACC	;GET REMAINDER
	MOV	A,H
	ANI	128	;Q-BIT MASK
	PUSH	PSW	;SAVE STATUS
	DAD	H	;2 X R(X)
	MOV	A,B	;GET BYTE
	ADD	L
	MOV	L,A
	POP	PSW
	JZ	CRCU1	;IF Q-BIT IS ZERO
;
	MOV	A,H
	XRI	0A0H	;MS HALF OF GEN. POLY
	MOV	H,A
	MOV	A,L
	XRI	97H	;LS HALF OF GEN. POLY
	MOV	L,A
;
CRCU1:
	SHLD	CRCACC	;SAVE RESULT
	POP	PSW	;RESTORE REGS
	POP	B
	POP	H
	RET

;
;  CRC Accumulator
;
CRCACC:
	DS	2	;2 BYTES

;
;  **** END OF CRC ROUTINES ****
;

;
;  BUFFERS
;
INSPECT:
	DS	1	; INSPECT FLAG (0=NO, 0FFH=YES)
COMMENT:
	DS	1	; CONTROL FLAG (0=NO, 0FFH=YES)
DSKOUT:
	DS	1	; DISK OUTPUT (0=NO, 0FFH=YES)
PRTOUT:
	DS	1	; PRINTER OUTPUT (0=NO, 0FFH=YES)
DISK:
	DS	1	; HOME DISK NUMBER
USER:
	DS	1	; HOME USER NUMBER
CDISK:
	DS	1	; CURRENT DISK NUMBER
CUSER:
	DS	1	; CURRENT USER NUMBER
NEXTCH:
	DS	2	; PTR TO NEXT CHAR IN MULTIFILE COMMAND LINE
FILECNT:
	DS	2	; COUNT OF NUMBER OF FILES RENAMED
NUMBUF:
	DS	5	; NUMBER STORAGE BUFFER
CRCFCB:
	DS	36	; FCB FOR CRC
NTFCB:
	DS	36	; FCB FOR NEW FILE
CMTLNE:
	DS	256	; COMMENT LINE BUFFER
CMDLNE:
	DS	256	; ALLOW MAX SIZE OF COMMAND LINE
	DS	100	; STACK AREA
STACK:
	DS	2	; OLD STACK PTR

	END
